package com.codeworker.app.ui.bill;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.IdRes;
import androidx.annotation.RequiresApi;

import com.codeworker.app.MainActivity;
import com.codeworker.app.R;
import com.codeworker.app.data.common.Constant;
import com.codeworker.app.data.common.enums.BillTypeEnum;
import com.codeworker.app.data.common.enums.PayTypeEnum;
import com.codeworker.app.data.entity.Bill;
import com.codeworker.app.data.entity.Property;
import com.codeworker.app.data.repository.BillRepository;
import com.codeworker.app.data.repository.PropertyRepository;
import com.codeworker.app.databinding.ActivityBillFormBinding;
import com.codeworker.app.ui.wrapper.MyBaseActivity;
import com.codeworker.app.ui.wrapper.MyPopupWindow;
import com.codeworker.app.ui.wrapper.MyPopupWindowAdapter;
import com.codeworker.app.ui.wrapper.MyTextWatcher;
import com.codeworker.app.utils.FormatUtil;
import com.codeworker.app.utils.MoneyUtil;
import com.codeworker.app.utils.ObjectUtil;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class ModifyBillActivity extends MyBaseActivity {

    private TextView tvPayType;
    private TextView tvPayTypeId;
    private TextView tvBillType;
    private TextView tvBillTypeId;
    private TextView tvBillBelong;
    private TextView tvBillBelongId;
    private TextView tvBillCreateTime;
    private TextView tvBillUpdateTime;
    private EditText etBillValue;
    private EditText etRemark;
    private Bill newBill;
    private Bill oldBill;
    private Button btn;
    private List<MyPopupWindowAdapter.PopupWindowViewHolderInDB> popupWindowItems;
    private PropertyRepository propertyRepository;

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityBillFormBinding binding = ActivityBillFormBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);
        setToolbar(this);

        initView(view);
        initData();
        dataChangeListener();
        btn.setOnClickListener(v -> btnClickEvent(newBill, oldBill, v));
    }

    private void initView(View view) {
        tvPayType = view.findViewById(R.id.tv_pay_type);
        tvPayTypeId = view.findViewById(R.id.tv_pay_type_id);
        tvBillType = view.findViewById(R.id.tv_bill_type);
        tvBillTypeId = view.findViewById(R.id.tv_bill_type_id);
        tvBillBelong = view.findViewById(R.id.tv_bill_belong);
        tvBillBelongId = view.findViewById(R.id.tv_bill_belong_id);
        etBillValue = view.findViewById(R.id.et_bill_value);
        etRemark = view.findViewById(R.id.et_bill_remark);
        tvBillCreateTime = view.findViewById(R.id.tv_bill_create_time);
        tvBillUpdateTime = view.findViewById(R.id.tv_bill_update_time);
        TableRow trBillCreateTime = view.findViewById(R.id.tr_bill_create_time);
        TableRow trBillUpdateTime = view.findViewById(R.id.tr_bill_update_time);
        btn = view.findViewById(R.id.btn_handle_bill);

        trBillCreateTime.setVisibility(View.VISIBLE);
        trBillUpdateTime.setVisibility(View.VISIBLE);
        btn.setEnabled(false);
    }

    private void initData() {
        //获取前置页面的参数
        Intent intent = getIntent();
        oldBill = (Bill) intent.getExtras().getSerializable(BillDailyListAdapter.ITEM_DATA);

        int payTypeId = oldBill.getPayType();
        setTextViewData(tvPayType, tvPayTypeId, PayTypeEnum.getPayTypeDesc(payTypeId), payTypeId);
        int billTypeId = oldBill.getType();
        setTextViewData(tvBillType, tvBillTypeId, BillTypeEnum.getBillDesc(payTypeId, billTypeId), billTypeId);

        propertyRepository = new PropertyRepository(this.getApplication());
        int billBelongId = oldBill.getPropertyId();
        Property property = propertyRepository.getPropertyById(billBelongId);
        String billBelong = Constant.HAS_DELETED.equals(property.getIsDeleted()) ?
                Constant.DELETED_MSG : property.getName();
        setTextViewData(tvBillBelong, tvBillBelongId, billBelong, billBelongId);

        etBillValue.setHint(FormatUtil.format(oldBill.getValue() * 1.0 / 100));
        etRemark.setHint(ObjectUtil.dataOrDefault(oldBill.getRemark().trim(), "(空)"));
        tvBillCreateTime.setHint(oldBill.getCreateTime());
        tvBillUpdateTime.setHint(ObjectUtil.dataOrDefault(oldBill.getUpdateTime(), "(暂无修改)"));

        newBill = Bill.clone(oldBill);
    }

    private void setTextViewData(TextView tv, TextView tvId, String hintStr, int tvIdInt) {
        tv.setText(null);
        tv.setHint(hintStr);
        tvId.setText(String.valueOf(tvIdInt));
    }

    private void dataChangeListener() {
        //监听弹窗变化
        tvPayType.setOnClickListener(v -> popupWindowEvent(v, R.id.tv_pay_type, tvPayType, tvPayTypeId));
        tvBillType.setOnClickListener(v -> popupWindowEvent(v, R.id.tv_bill_type, tvBillType, tvBillTypeId));
        tvBillBelong.setOnClickListener(v -> popupWindowEvent(v, R.id.tv_bill_belong, tvBillBelong, tvBillBelongId));

        //监听文本变化
        tvPayType.addTextChangedListener(tvPayTypeChangeListenerEvent());
        tvBillType.addTextChangedListener(tvBillTypeChangeListenerEvent());
        tvBillBelong.addTextChangedListener(tvBillBelongChangeListenerEvent());
        etBillValue.addTextChangedListener(etBillValueChangeListenerEvent());
        etRemark.addTextChangedListener(etRemarkChangeListenerEvent());
    }

    //TODO 复用代码 设置弹窗事件
    @SuppressLint("NonConstantResourceId")
    @RequiresApi(api = Build.VERSION_CODES.N)
    private void popupWindowEvent(View v, @IdRes int viewId, TextView tv, TextView tvId) {
        @SuppressLint("InflateParams") View popUpView
                = LayoutInflater.from(v.getContext()).inflate(R.layout.layout_common_popup, null);
        //设置适配器的数据项
        ListView listView = popUpView.findViewById(R.id.lv_common_popup);
        switch (viewId) {
            case R.id.tv_pay_type:
                popupWindowItems = Arrays.stream(PayTypeEnum.values())
                        .map(data -> new MyPopupWindowAdapter.PopupWindowViewHolderInDB(
                                data.getPayTypeDesc(), data.getPayTypeInDB()))
                        .collect(Collectors.toList());
                break;
            case R.id.tv_bill_type:
                int billType = Integer.parseInt(tvPayTypeId.getText().toString());
                popupWindowItems = Arrays.stream(BillTypeEnum.values())
                        .filter(data -> data.getPayType().equals(billType))
                        .map(data -> new MyPopupWindowAdapter.PopupWindowViewHolderInDB(
                                data.getBillTypeDesc(), data.getBillTypeInDB()))
                        .collect(Collectors.toList());
                break;
            case R.id.tv_bill_belong:
                popupWindowItems = propertyRepository.getProperties().stream()
                        .map(data -> new MyPopupWindowAdapter.PopupWindowViewHolderInDB(
                                data.getName(), data.getId()))
                        .collect(Collectors.toList());
                break;
            default:
                break;
        }
        //初始化适配器
        MyPopupWindowAdapter adapter = new MyPopupWindowAdapter(v.getContext(), popupWindowItems);
        listView.setAdapter(adapter);
        //设置弹窗
        boolean isFixedPopupWindowHeight = popupWindowItems.size() > MyPopupWindow.MAX_POPUP_WINDOW_ITEMS_SIZE;
        MyPopupWindow myPopupWindow = new MyPopupWindow(popUpView, this, isFixedPopupWindowHeight);

        //弹出创建显示在按钮下面
        myPopupWindow.showAtLocation(v, Gravity.BOTTOM, 0, 0);
        //弹窗事件监听
        AtomicInteger idInDB = new AtomicInteger();
        listView.setOnItemClickListener((parent, view, position, id) -> {
            tv.setText(popupWindowItems.get(position).getItem());
            idInDB.set(popupWindowItems.get(position).getId());
            tvId.setText(String.valueOf(popupWindowItems.get(position).getId()));
            //关闭弹出框
            myPopupWindow.dismiss();
            //如果弹窗是收支类型，则相关的记账类型随之变动
            if (PayTypeEnum.INCOME.getPayTypeDesc().equals(tv.getText().toString())) {
                tvBillType.setText(BillTypeEnum.IN_SALARY.getBillTypeDesc());
                tvBillTypeId.setText(String.valueOf(BillTypeEnum.IN_SALARY.getBillTypeInDB()));
            }
            if (PayTypeEnum.EXPEND.getPayTypeDesc().equals(tv.getText().toString())) {
                tvBillType.setText(BillTypeEnum.EX_EAT.getBillTypeDesc());
                tvBillTypeId.setText(String.valueOf(BillTypeEnum.EX_EAT.getBillTypeInDB()));
            }
        });
        idInDB.get();
    }

    private MyTextWatcher tvPayTypeChangeListenerEvent() {
        return new MyTextWatcher() {
            @Override
            public void afterTextChanged(Editable editable) {
                btn.setEnabled(true);
                int payTypeId = PayTypeEnum.EXPEND.getPayTypeInDB();
                if (PayTypeEnum.EXPEND.getPayTypeDesc().equals(editable.toString())) {
                    newBill.setType(BillTypeEnum.EX_EAT.getBillTypeInDB());
                } else {
                    payTypeId = PayTypeEnum.INCOME.getPayTypeInDB();
                    newBill.setType(BillTypeEnum.IN_SALARY.getBillTypeInDB());
                }
                newBill.setPayType(payTypeId);
            }
        };
    }

    private MyTextWatcher tvBillTypeChangeListenerEvent() {
        return new MyTextWatcher() {
            @Override
            public void afterTextChanged(Editable editable) {
                int billTypeId = Arrays.stream(BillTypeEnum.values())
                        .filter(data -> data.getBillTypeDesc().equals(editable.toString()))
                        .map(BillTypeEnum::getBillTypeInDB)
                        .findFirst()
                        .orElseThrow(() -> {
                            Toast.makeText(getApplication(), R.string.toast_unknown_error, Toast.LENGTH_SHORT).show();
                            return null;
                        });
                textChangeEvent(billTypeId, newBill::setType);
            }
        };
    }

    private <T> void textChangeEvent(T data, Consumer<T> consumer) {
        btn.setEnabled(true);
        consumer.accept(data);
    }

    private MyTextWatcher tvBillBelongChangeListenerEvent() {
        return new MyTextWatcher() {
            @Override
            public void afterTextChanged(Editable editable) {
                int billBelongId = propertyRepository.getProperties()
                        .stream()
                        .filter(data -> data.getName().equals(editable.toString()))
                        .map(Property::getId)
                        .findFirst()
                        .orElseThrow(() -> {
                            Toast.makeText(getApplication(), R.string.toast_unknown_error, Toast.LENGTH_SHORT).show();
                            return null;
                        });
                textChangeEvent(billBelongId, newBill::setPropertyId);
            }
        };
    }

    private MyTextWatcher etBillValueChangeListenerEvent() {
        return new MyTextWatcher() {
            @Override
            public void afterTextChanged(Editable editable) {
                super.afterTextChanged(editable);
                textChangeEvent((int) (MoneyUtil.mul(Double.parseDouble(etBillValue.getText().toString()), 100)),
                        newBill::setValue);
            }
        };
    }

    private MyTextWatcher etRemarkChangeListenerEvent() {
        return new MyTextWatcher() {
            @Override
            public void afterTextChanged(Editable editable) {
                textChangeEvent(etRemark.getText().toString(), newBill::setRemark);
            }
        };
    }

    private void btnClickEvent(Bill newBill, Bill oldBill, View view) {
        newBill.setUpdateTime(FormatUtil.format(LocalDateTime.now()));
        BillRepository billRepository = new BillRepository(getApplication());
        billRepository.update(newBill, oldBill);
        Intent intent = new Intent(view.getContext(), MainActivity.class);
        startActivity(intent);
    }
}
